package com.nineclock.approve.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.nineclock.approve.dto.*;
import com.nineclock.approve.mapper.ApproveDefinitionMapper;
import com.nineclock.approve.pojo.ApproveDefinition;
import com.nineclock.approve.service.ActivitiService;
import com.nineclock.approve.service.ApproveDefinitionService;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.CurrentUserHolder;
import com.nineclock.common.utils.JsonUtils;
import com.nineclock.common.utils.UUIDUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Transactional
@Service
@Slf4j
public class ApproveDefinitionServiceImpl implements ApproveDefinitionService {

    @Autowired
    private ApproveDefinitionMapper approveDefinitionMapper;
    @Autowired
    ActivitiService activitiService;

    @Override
    public List<ApproveGroupDefinitionDto> queryApproveGroupDefinition() {
        List<ApproveGroupDefinitionDto> definitionDtoList=new ArrayList<>();

        LambdaQueryWrapper<ApproveDefinition> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ApproveDefinition::getCompanyId, CurrentUserHolder.get().getCompanyId());
        lambdaQueryWrapper.eq(ApproveDefinition::getIsValid,"1");

        List<ApproveDefinition> approveDefinitions = approveDefinitionMapper.selectList(lambdaQueryWrapper);

        if (CollectionUtil.isNotEmpty(approveDefinitions)){
            Map<String, List<ApproveDefinition>> listMap = approveDefinitions.stream().collect(Collectors.groupingBy(ApproveDefinition::getGroupType));

            for (String groupType : listMap.keySet()) {
                ApproveGroupDefinitionDto approveGroupDefinitionDto=new ApproveGroupDefinitionDto();
                approveGroupDefinitionDto.setGroupType(groupType);
                approveGroupDefinitionDto.setDefinitionList(listMap.get(groupType));
                definitionDtoList.add(approveGroupDefinitionDto);
            }
        }

        return definitionDtoList;
    }

    ApproveDefinition definition = null;

    @Override
    public void saveApproveDefinition(ApproveDefinitionSaveDto approveDefinitionSaveDto) {
        ApproveDefinitionBaseDataDto baseData = approveDefinitionSaveDto.getBaseData();
        if (baseData==null){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        ApproveDefinition definition = null;

        //新增
        if (StrUtil.isEmpty(baseData.getId())){
//            组装定义基础信息
            BeanHelper.copyProperties(baseData,ApproveDefinition.class,"allowUserJson");
//            类型不匹配（用户自己操作）
            definition.setAllowUserJson(JsonUtils.toString(baseData.getAllowUserJson()));

            //组装流程定义的表单信息
            definition.setFormJson(JsonUtils.toString(approveDefinitionSaveDto.getTableData()));

//            后续使用
            definition.setTableName("flow_"+ UUIDUtils.getUUID());
//          需要将所有的表单信息，记录下来并且拓展参数，fieldKey
            definition.setColumns(JsonUtils.toString(expandFieldKey(approveDefinitionSaveDto)));

            //组装流程定义的流程信息 ---> 后续拓展使用
            JSONArray jsonArray = JSONUtil.parseArray(approveDefinitionSaveDto.getFlowData());
            expandParamWithNodeKey(jsonArray);
            definition.setFlowJson(JSONUtil.toJsonStr(jsonArray));

            //组装流程定义的其他信息
            definition.setDataFrom("1");
            definition.setIsValid("1");// 1表示此流程有效
            definition.setCompanyId(CurrentUserHolder.get().getCompanyId()+"");

            approveDefinitionMapper.insert(definition);
        }else {
            ////根据id更新 审批流程
            approveDefinitionMapper.updateById(definition);
//            删除activiti 中 审批流程
            activitiService.dropProcessFromActiviti(definition);
//            部署审批流程 到 Activiti
            activitiService.deployProcessToActiviti(definition);
        }

        // 审批流程部署 ----> 需要将页面审批流程中涉及的流程图, 部署到Activiti引擎中 ;
        approveDefinitionMapper.insert(definition);
        activitiService.deployProcessToActiviti(definition);

    }

    private void expandParamWithNodeKey(JSONArray jsonArray) {
        for(int i = 0; i < jsonArray.size(); i++){
            JSONObject jsonNode = (JSONObject) jsonArray.get(i);

            String nodeKey = jsonNode.getStr("nodeKey");
            if(StrUtil.isEmpty(nodeKey)){
                jsonNode.put("nodeKey", UUIDUtils.getUUID());
            }

            //处理网关节点的内部节点 nodeKey
            String type = jsonNode.getStr("type");
            if("condition".equals(type)){

                JSONArray batchArray = (JSONArray) jsonNode.get("node");
                if(batchArray!=null && batchArray.size()>0){

                    for (int j = 0; j < batchArray.size(); j++) {
                        JSONArray innerArray = (JSONArray) batchArray.get(j);

                        if(innerArray!=null && innerArray.size()>0){
                            for (int k = 0; k < innerArray.size(); k++) {
                                JSONObject node = (JSONObject) innerArray.get(k);
                                if(!node.containsKey("nodeKey")){
                                    node.put("nodeKey", UUIDUtils.getUUID());
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 扩充参数 : fieldKey
     * @param approveDefinitionDto
     * @return
     */
    private List<ColumnObjDto> expandFieldKey(ApproveDefinitionSaveDto approveDefinitionDto) {
        List<ColumnObjDto> columns = new ArrayList<>();

        for (ApproveDefinitionTableDataDto tableData : approveDefinitionDto.getTableData()) {
            if(StrUtil.isEmpty(tableData.getFieldKey())){
                tableData.setFieldKey(UUIDUtils.getUUID());
            }

            columns.add(new ColumnObjDto(tableData.getFieldKey(), tableData.getLab(), tableData.getTitle(), "1"));
        }
        return columns;
    }
}
